import hashlib
import numpy as np
from numpy.random import default_rng
import matplotlib.pyplot as plt
import chaos_and_logistic_new as cal

# 密钥流产生器
# PLM 映射函数
# num_segments：分段的段数，控制系统的混沌程度和分段的粒度。
def piecewise_logistic_map(x, r, num_segments,j):
    segment_length = 1.0 / num_segments
    # print(j)
    a = ""
    for i in range(num_segments):
        left_segment = i * segment_length
        right_segment = (i + 1) * segment_length
        if x > left_segment and  x < right_segment:
            if i % 2 == 0:
                x = num_segments * num_segments * r *(x - left_segment) * (right_segment - x) 
            else:
                x = 1 - (num_segments * num_segments * r * (x - left_segment) * (right_segment - x))
            break
        elif x == i / num_segments and x != 1:
            x = x + 1.0 /(num_segments)
            break
        elif x == 1:
            x = x - 1.0 /(num_segments)
            break
    return x

# generate_key函数是生成密钥的函数，其参数包括：
# seed_str：种子值，用于初始化Logistic映射的状态值。
def generate_key_stream(seed_str, r, num_segments, key_length):
    key = []
    x = key_to_hash(seed_str)
    print("x:"+str(x))
    for j in range(key_length):
        x = piecewise_logistic_map(x, r, num_segments,j)
        # key.append(int(x * 10000) % 256) # 取最后两位小数作为密钥的一个字节
        key.append(x)
    return key
 
#  密钥获取hash函数
def key_to_hash(seed_str):
    # 计算字符串的哈希值
    sha256 = hashlib.sha256(seed_str.encode()).digest()
    # 使用哈希值作为种子
    rng = default_rng(int.from_bytes(sha256, "big"))
    # 生成随机数
    r = rng.random()
    # 保留两位小数
    r = np.round(r, decimals=2)
    # 输出结果
    return r

# 将状态值转化为二进制
def decimal_array_to_binary(decimal_array):
    binary_array = []
    for decimal in decimal_array:
        binary = ""
        while decimal != 0:
            decimal *= 2
            if decimal >= 1:
                binary += "1"
                decimal -= 1
            else:
                binary += "0"
            if len(binary) > 64:  # 设置精度为32位，防止死循环
                break
        binary_array.append(binary[8:16])
    return binary_array


# 绘制密度概率图
def showChart(data):
    # 计算概率分布
    counts, bins = np.histogram(data, bins=256)
    probs = counts / sum(counts) * 100

    # 绘制概率分布图
    plt.bar(bins[:-1], probs, width=0.004, alpha=0.7)
    plt.rcParams['font.sans-serif'] = ['SimSun']  # 设置中文字体为宋体
    plt.rcParams['font.serif'] = ['Times New Roman']  # 设置西文字体为Times New Roman

    # 解决负号'-'显示为方块的问题
    plt.rcParams['axes.unicode_minus'] = False

    plt.ylim([0, 5.0])
    # plt.yticks([0,0.5,1.0,1.5,2.0])
    plt.yticks([0,0.5,1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0])

    plt.xlim([0, 1])
    # plt.xticks([0,25,50,75,100,125,150,175,200,225,250])
    plt.xticks([0,0.2,0.4,0.6,0.8,1.0])

    # 添加标题和标签
    # plt.title('logistic map')
    plt.xticks(fontsize=24)
    plt.yticks(fontsize=24)
    plt.xlabel('x',fontsize=24)
    plt.ylabel('百分比 (%)',fontsize=24)

    # 显示图像
    plt.show()


def ss_chart(keylen,data):
    plt.scatter(range(keylen), data, s=5)
    plt.rcParams['font.sans-serif'] = ['SimSun']  # 设置中文字体为宋体
    plt.rcParams['font.serif'] = ['Times New Roman']  # 设置西文字体为Times New Roman

    # 解决负号'-'显示为方块的问题
    plt.rcParams['axes.unicode_minus'] = False
    plt.xlabel('迭代次数',fontsize=24)
    plt.ylabel('状态值',fontsize=24)
    plt.ylim([0, 1.0])
    plt.xlim([0, 50000])
    plt.xticks(fontsize=24)
    plt.yticks(fontsize=24)
    # plt.title(f'Logistic Scatter Plot')
    plt.show()


if __name__ == '__main__':
    seed_str = "this is a key akk" #密钥key
    u = 4         #迭代状态值u->(0,4)
    n = 64            #映射的分段总数
    key_length  = 50000  # key_length：生成的密钥长度，单位为字节
    key = generate_key_stream(seed_str, u, n, key_length)
    
    print("key stream:",key)
    ss_chart(key_length,key)

    
    # # decimal_array = [0.625, 0.25, 0.75]
    # binary_array = decimal_array_to_binary(key)
    # decimal_list = [int(binary, 2) for binary in binary_array]
    # print(decimal_list)  
#     data = key

   
   # 计算概率分布
    showChart(key)





   




